<?php

namespace EventServer;

use Redis;

/**
 * Event Server Connection
 *
 * @author zan <zan@big3fire.com>
 */
class Connection
{
    const MAP_KEY = 'eventserver/map';
    
    const CHANNEL_PREFIX = 'eventserver/channel/';
    
    private $redis;
    
    private $server;
    
    private $fd;
    
    /**
     * 
     * @param Redis $redis
     * @param swoole_websocket_server $server
     * @param integer $fd
     */
    public function __construct($redis, $server, $fd)
    {
        $this->redis = $redis;
        $this->server = $server;
        $this->fd = $fd;
    }
    
    /**
     * 
     * @param string $channel
     * @return boolean
     */
    public function subscribe($channel)
    {
        $channel = static::CHANNEL_PREFIX . $channel;
        $type = $this->redis->type($channel);
        if($type == Redis::REDIS_SET) {
            if($this->redis->sismember($channel, $this->fd)) {
                if($this->server->exist($this->fd)) {
                    return FALSE;
                }
                $this->redis->sRemove($channel, $this->fd);
            }
        }
        
        return $this->redis->sAdd($channel, $this->fd);
    }
    
    public function publish($channel, $content)
    {
        $success = 0;
        
        $channel = static::CHANNEL_PREFIX . $channel;
        
        if(is_array($content)) {
            $content = json_encode($content);
        }
        
        $type = $this->redis->type($channel);
        if($type == Redis::REDIS_SET) {
            $members = $this->redis->sMembers($channel);
            foreach($members as $member) {
                if($this->server->exist($member)) {
                   $this->server->push($member, $content); 
                   $success++;
                } else {
                    $this->redis->sRemove($channel, $member);
                }
            }
        }
        return $success;
    }
    
    public function register($sessionid)
    {
        if(!is_string($sessionid) || !$sessionid) {
            return FALSE;
        }
        
        if($this->redis->type(static::MAP_KEY) == Redis::REDIS_HASH) {
            if($this->redis->hExists(static::MAP_KEY, $sessionid)) {
                $fd = $this->redis->hGet(static::MAP_KEY, $sessionid);
                if($this->server->exist($fd)) {
                    return FALSE;
                }
                $this->redis->hDel(static::MAP_KEY, $sessionid);
            }
        }
        
        return $this->redis->hSet(static::MAP_KEY, $sessionid, $this->fd);
    }
    
    public function notify($sessionid, $content)
    {
        if(is_array($content)) {
            $content = json_encode($content);
        }
        
        if(is_array($sessionid) && isset($sessionid[0])) {
            $success = 0;
            if(is_array($sessionid)) {
                foreach($sessionid as $sessionidItem) {
                    if($this->push($sessionidItem, $content)) {
                        $success++;
                    }
                }
            }
            return $success;
        }else if(is_string($sessionid) && $sessionid) {
            if($this->redis->hExists(static::MAP_KEY, $sessionid)) {
                $fd = $this->redis->hGet(static::MAP_KEY, $sessionid);
                if($this->server->exist($fd)) {
                    return $this->server->push($fd, $content);
                }
                $this->redis->hDel(static::MAP_KEY, $sessionid);
            }
        }
        return false;
    }
    
    public function clear()
    {
        $success = 0;
        if($this->redis->type(static::MAP_KEY) == Redis::REDIS_HASH) {
            foreach ($this->redis->hKeys(static::MAP_KEY) as $key) {
                $fd = $this->redis->hGet(static::MAP_KEY, $key);
                if(!$this->server->exist($fd)) {
                    $this->redis->hDel(static::MAP_KEY, $key);
                    $success++;
                }
            }
        }
        return $success;
    }
    
    public function close()
    {
        foreach ($this->redis->hKeys(static::MAP_KEY) as $key) {
            if ($this->fd == $this->redis->hGet(static::MAP_KEY, $key)) {
                $this->redis->hDel(static::MAP_KEY, $key);
                return $key;
            }
        }
    }
}
